package tomkitty.server;

import tomkitty.turdlet.*;
import tomkitty.util.*;
import java.io.*;
import java.net.*;

/**
 *
 * <code>ConnectionHandler</code> takes care of handling requests for the 
 * <code>Server</code> class. The http header is examined and the requested 
 * resource is returned, if
 * possible. If the resource is the name of a turdlet, then a turdlet of
 * that type is instantiated and connected to the input and output buffers,
 * and all IO is then handled by the turdlet. Otherwise, if no turdlet can
 * be found to correspond with the resource name or if an exception is
 * thrown somewhere, an <code>ErrorTurdlet</code> will be instantiated 
 * to return an
 * appropriate response. Currently only the GET and HEAD HTTP methods are
 * implemented, but POST will be included eventually.
 *
 * @author alan
 * @author micha
 */
public class ConnectionHandler extends Thread implements HttpConstants {

	private Socket sin = null;
	private ConnectionHandlerPool pool = null;
	private TurdletFactory factory = null;

	/**
	 * Gets the factory member of this class.
	 *
	 * @return The turdlet factory
	 */
	public TurdletFactory getFactory() {
		return factory;
	}

	/**
	 * Sets the socket this handler is waiting on. This method will wake up
	 * this sleeping thread if the socket parameter is not null.
	 *
	 * @param s incoming socket connection. Must be the result of a call to
	 * 					<code>accept</code> or similar.
	 */
	public synchronized void setSocket(Socket s) {
		sin = s;
		notify();
	}

	/**
	 * Sets the <code>ConnectionHandlerPool</code> that this object belongs to. 
	 * This method is really only meant to be used by the 
	 * <code>ConnectionHandlerPool</code> class.
	 *
	 * @param p the pool the object belongs to.
	 */
	public synchronized void setPool(ConnectionHandlerPool p) {
		pool = p;
	}

	/**
	 * Handles the connection.
	 */
	public synchronized void run() {

		// if we haven't yet instantiated a factory for this thread we do it now

		if (factory == null) {
			factory = new TurdletFactory();
		}

		// server listen loop, sort of. we loop around getting newly connected
		// sockets.

		while (true) {

			// wait until a socket is assigned to sin

			try {
				if (sin == null) {
					wait();
				}
			} catch(InterruptedException e) {
				e.printStackTrace();	
			}

			// socket is assigned. it will already be connected and ready.

			try {

				factory.runTurdlet(
						factory.create(new TurdletContext(sin, null, null, this))
					);

				sin.close();
				sin = null;

				// try to reuse this thread. pool has to be explicitly set after
				// this class is instantiated for recycle() to actually do anything.

				if (pool != null) {
					pool.recycle(this);
				}

			} catch(IOException e) {

				e.printStackTrace();

			}
		}
	}

}
